package com.ys.service.finance.impl;

import com.alibaba.fastjson.JSON;
import com.ys.dto.AddDto;
import com.ys.dto.EditDto;
import com.ys.entity.finance.TcwDepositPlatform;
import com.ys.entity.finance.TcwDepositPlatformAccount;
import com.ys.entity.finance.TcwOperateCompanyPrepayment;
import com.ys.entity.finance.TcwOperateCompanyPrepaymentFlow;
import com.ys.entity.flow.YspModel;
import com.ys.entity.sys.TsUserChange;
import com.ys.entity.sys.YsCol;
import com.ys.entity.sys.YsMenu;
import com.ys.enume.finance.TcwOperateCompanyPrepaymentFlowEnum;
import com.ys.mapper.finance.FinanceMapper;
import com.ys.mapper.finance.TcwOperateCompanyPrepaymentFlowMapper;
import com.ys.mapper.finance.TcwOperateCompanyPrepaymentMapper;
import com.ys.service.finance.TcwOperateCompanyPrepaymentService;
import com.ys.util.CheckUtil;
import com.ys.util.DateUtil;
import com.ys.util.shiro.ShiroUtils;
import com.ys.vo.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 运营公司预付款管理
 */
@Service("tcwOperateCompanyPrepaymentService")
public class TcwOperateCompanyPrepaymentServiceImpl implements TcwOperateCompanyPrepaymentService {
	private static final Logger logger = LoggerFactory.getLogger(TcwOperateCompanyPrepaymentServiceImpl.class);

	@Autowired
	private TcwOperateCompanyPrepaymentMapper tcwOperateCompanyPrepaymentMapper;

	@Autowired
	private FinanceMapper financeMapper;

	@Autowired
	private CheckUtil checkUtil;


	@Autowired
	private TcwOperateCompanyPrepaymentFlowMapper tcwOperateCompanyPrepaymentFlowMapper;



	/**
	 * 新增
	 */
	@Override
	@Transactional(timeout=120,propagation= Propagation.REQUIRES_NEW)
	public R add(Map<String, Object> params, Long menuId) throws Exception{
		logger.info("新增传参:"+params);
		//参数验证
		String errorBack = checkParams(params, menuId);
		if(errorBack!=null && !"".equals(errorBack)){
			return R.error(errorBack);
		}
		Map<String,Object> paramsAfterTrim = doTrim(params);
		TcwOperateCompanyPrepayment entity = JSON.parseObject(JSON.toJSONString(paramsAfterTrim), TcwOperateCompanyPrepayment.class);
		entity.setStatus(1);//状态

		int idAdd = new TcwOperateCompanyPrepayment()
				.setVgsbm(entity.getVgsbm()) //运营公司编码
				.setFkVid(entity.getFkVid()) //付款账户编码
				.setVid(entity.getVid()) //收款账户编码
				.setOperateCompanyPrepaymentType(entity.getOperateCompanyPrepaymentType()) //账号类型
				.count();
		if(idAdd>0){
			return R.error("该运营公司、付款账户编码、收款账户编码、账号类型已经新增过，无需再次新增");
		}


		//新增
		tcwOperateCompanyPrepaymentMapper.insert(entity);


		//新增流水
		{
			try {
				TcwOperateCompanyPrepaymentFlow flowInfo = new TcwOperateCompanyPrepaymentFlow()
						.setOperateCompanyPrepaymentId(entity.getId())//运营公司预付款管理表id
						.setPreAmountChange(entity.getPreAmount())
						.setInvoicingAmountChange(entity.getInvoicingAmount())
						.setWithholdAmountChange(entity.getWithholdAmount())
						.setPreReturnAmountChange(entity.getPreReturnAmount())//变动金额

						.setPreAmountAfter(entity.getPreAmount())
						.setInvoicingAmountAfter(entity.getInvoicingAmount())
						.setWithholdAmountAfter(entity.getWithholdAmount())
						.setPreReturnAmountAfter(entity.getPreReturnAmount())//变动后金额

						.setUserId(ShiroUtils.getUserId())//操作人工号
						.setFromType(TcwOperateCompanyPrepaymentFlowEnum.FromType.ADD.value)//来源类型
						.setFromBid("0")//来源工号
						.setStatus(1)
						.setRemark(params.get("remark")!=null?params.get("remark").toString():"")//备注
						;
				tcwOperateCompanyPrepaymentFlowMapper.insert(flowInfo);
			}catch (Exception e){
				logger.error("新增运营公司预付款管理流水失败",e);
			}
		}


		//return R.ok(EditDto.closeAndReload());
		return R.ok(AddDto.gotoEdit("/web/finance/tcwOperateCompanyPrepayment/toEdit?id=" + entity.getId()));
	}



	/**
	 * 编辑
	 */
	@Override
	@Transactional(timeout=120,propagation= Propagation.REQUIRES_NEW)
	public R edit(Map<String, Object> params, Long menuId) throws Exception{
		logger.info("编辑:"+params);
		//参数验证
		String errorBack = checkParams(params, menuId);
		if(errorBack!=null && !"".equals(errorBack)){
			return R.error(errorBack);
		}
		Map<String,Object> paramsAfterTrim = doTrim(params);
		TcwOperateCompanyPrepayment entity = JSON.parseObject(JSON.toJSONString(paramsAfterTrim), TcwOperateCompanyPrepayment.class);
		//entity.setStatus(1);//状态


		TcwOperateCompanyPrepayment oldInfo = new TcwOperateCompanyPrepayment().setId(entity.getId()).queryFirst();

		//编辑
		tcwOperateCompanyPrepaymentMapper.update(entity);


		//新增流水
		{
			try {
				TcwOperateCompanyPrepaymentFlow flowInfo = new TcwOperateCompanyPrepaymentFlow()
						.setOperateCompanyPrepaymentId(entity.getId())//运营公司预付款管理表id
						.setPreAmountChange(((entity.getPreAmount()!=null?entity.getPreAmount():BigDecimal.ZERO)).subtract((oldInfo.getPreAmount()!=null?oldInfo.getPreAmount():BigDecimal.ZERO)))
						.setInvoicingAmountChange(((entity.getInvoicingAmount()!=null?entity.getInvoicingAmount():BigDecimal.ZERO)).subtract((oldInfo.getInvoicingAmount()!=null?oldInfo.getInvoicingAmount():BigDecimal.ZERO)))
						.setWithholdAmountChange(((entity.getWithholdAmount()!=null?entity.getWithholdAmount():BigDecimal.ZERO)).subtract((oldInfo.getWithholdAmount()!=null?oldInfo.getWithholdAmount():BigDecimal.ZERO)))
						.setPreReturnAmountChange(((entity.getPreReturnAmount()!=null?entity.getPreReturnAmount():BigDecimal.ZERO)).subtract((oldInfo.getPreReturnAmount()!=null?oldInfo.getPreReturnAmount():BigDecimal.ZERO)))//变动金额

						.setPreAmountAfter(entity.getPreAmount())
						.setInvoicingAmountAfter(entity.getInvoicingAmount())
						.setWithholdAmountAfter(entity.getWithholdAmount())
						.setPreReturnAmountAfter(entity.getPreReturnAmount())//变动后金额

						.setUserId(ShiroUtils.getUserId())//操作人工号
						.setFromType(TcwOperateCompanyPrepaymentFlowEnum.FromType.EDIT.value)//来源类型
						.setFromBid("0")//来源工号
						.setStatus(1)
						.setRemark(params.get("remark")!=null?params.get("remark").toString():"")//备注
						;
				tcwOperateCompanyPrepaymentFlowMapper.insert(flowInfo);
			}catch (Exception e){
				logger.error("新增运营公司预付款管理流水失败",e);
			}
		}


		return R.ok(EditDto.closeAndReload());
	}




	/**
	 * 新增或累加
	 * @param vgsbm 运营公司编码
	 * @param fkVid 付款账户编码
	 * @param fkVyhzh 付款账号
	 * @param fkVkhh 付款开户行
	 * @param fkVyhzhmc 付款账户名称
	 * @param vid 收款账户编码
	 * @param vyhzh 收款账号
	 * @param vkhh 收款开户行
	 * @param vyhzhmc 收款账户名称
	 * @param operateCompanyPrepaymentType 账号类型（0.公司对公账户|1.万里汇）
	 * @param preAmount 预付款金额
	 * @param invoicingAmount 开票金额
	 * @param withholdAmount 代扣代缴金额
	 * @param preReturnAmount 预付款退回金额
	 * @param remark 备注
	 * @return  R SUCCESS("成功", 0), FAILED("失败", 1); 失败原因：R.getMsg()
	 */
	@Override
	public R addOrAccrual(String vgsbm, String fkVid, String fkVyhzh, String fkVkhh, String fkVyhzhmc,
						  String vid, String vyhzh, String vkhh, String vyhzhmc,int operateCompanyPrepaymentType,
						  BigDecimal preAmount,BigDecimal invoicingAmount,BigDecimal withholdAmount,BigDecimal preReturnAmount,
						  String userId,int fromType,String fromBid,String remark) throws Exception{
		logger.info("新增数据");

		//根据：vgsbm 运营公司编码、fkVid 付款账户编码、vid 收款账户编码、operateCompanyPrepaymentType 账号类型
		//判断：新增 Or 累加

		TcwOperateCompanyPrepayment entity = new TcwOperateCompanyPrepayment()
				.setVgsbm(vgsbm) //运营公司编码
				.setFkVid(fkVid) //付款账户编码
				.setVid(vid) //收款账户编码
				.setOperateCompanyPrepaymentType(operateCompanyPrepaymentType); //账号类型

		TcwOperateCompanyPrepayment hasAdd = entity.queryFirst();


		BigDecimal preAmountAfter = BigDecimal.ZERO ,
				invoicingAmountAfter = BigDecimal.ZERO,
				withholdAmountAfter = BigDecimal.ZERO,
				preReturnAmountAfter = BigDecimal.ZERO;

		boolean isNew = true;//是否新增
		if(hasAdd!=null && hasAdd.getId()!=null){//累加
			entity.setId(hasAdd.getId());
			isNew = false;
			if(hasAdd.getPreAmount()!=null) preAmountAfter = hasAdd.getPreAmount().add(preAmount);//预付款金额
			if(hasAdd.getInvoicingAmount()!=null) invoicingAmountAfter = hasAdd.getInvoicingAmount().add(invoicingAmount);//开票金额
			if(hasAdd.getWithholdAmount()!=null) withholdAmountAfter = hasAdd.getWithholdAmount().add(withholdAmount);//预付款退回金额
			if(hasAdd.getPreReturnAmount()!=null) preReturnAmountAfter = hasAdd.getPreReturnAmount().add(preReturnAmount);//预付款金额
		}else {//新增
			entity.setStatus(1);
			preAmountAfter = preAmount;
			invoicingAmountAfter = invoicingAmount;
			withholdAmountAfter = withholdAmount;
			preReturnAmountAfter = preReturnAmount;
		}

		//预付款剩余金额 = 预付款金额-开票金额-代扣代缴-预付款退回金额
		BigDecimal preResAmount = preAmountAfter
				.subtract(invoicingAmountAfter)
				.subtract(withholdAmountAfter)
				.subtract(preReturnAmountAfter);

		entity.setFkVyhzh(fkVyhzh);//付款账号
		entity.setFkVkhh(fkVkhh);//付款开户行
		entity.setFkVyhzhmc(fkVyhzhmc);//付款账户名称
		entity.setVyhzh(vyhzh);//收款账号
		entity.setVkhh(vkhh);//收款开户行
		entity.setVyhzhmc(vyhzhmc);//收款账户名称
		entity.setPreAmount(preAmountAfter);//预付款金额
		entity.setInvoicingAmount(invoicingAmountAfter);//开票金额
		entity.setWithholdAmount(withholdAmountAfter);//预付款退回金额
		entity.setPreReturnAmount(preReturnAmountAfter);//预付款金额
		entity.setPreResAmount(preResAmount);//预付款剩余金额

		if (isNew){
			tcwOperateCompanyPrepaymentMapper.insert(entity);
		}else {
			tcwOperateCompanyPrepaymentMapper.update(entity);
		}


		//新增流水
		{
			try {
				TcwOperateCompanyPrepaymentFlow flowInfo = new TcwOperateCompanyPrepaymentFlow()
						.setOperateCompanyPrepaymentId(entity.getId())//运营公司预付款管理表id
						.setPreAmountChange(preAmount)
						.setInvoicingAmountChange(invoicingAmount)
						.setWithholdAmountChange(withholdAmount)
						.setPreReturnAmountChange(preReturnAmount)//变动金额

						.setPreAmountAfter(preAmountAfter)
						.setInvoicingAmountAfter(invoicingAmountAfter)
						.setWithholdAmountAfter(withholdAmountAfter)
						.setPreReturnAmountAfter(preReturnAmountAfter)//变动后金额

						.setUserId(userId)//操作人工号
						.setFromType(fromType)//来源类型
						.setFromBid(fromBid)//来源工号
						.setRemark(remark)
						.setStatus(1);
				tcwOperateCompanyPrepaymentFlowMapper.insert(flowInfo);
			}catch (Exception e){
				logger.error("新增运营公司预付款管理流水失败",e);
			}
		}

		return R.ok();
	}



	/**
	 * 万里汇单据：新增或累加（收款账户为默认值）
	 * @param vgsbm 运营公司编码
	 * @param depositPlatformCode 收款平台账号Code（TCW_DepositPlatform）
	 * @param preAmount 预付款金额
	 * @param invoicingAmount 开票金额
	 * @param withholdAmount 代扣代缴金额
	 * @param preReturnAmount 预付款退回金额
	 * @param remark 备注
	 * @return  R SUCCESS("成功", 0), FAILED("失败", 1); 失败原因：R.getMsg()
	 */
	@Override
	public R addOrAccrualWanliInfo(String vgsbm,String depositPlatformCode,BigDecimal preAmount,
							BigDecimal invoicingAmount,BigDecimal withholdAmount,BigDecimal preReturnAmount,
							String userId,int fromType,String fromBid,String remark) throws Exception{

		TcwDepositPlatform entity = new TcwDepositPlatform().setCode(depositPlatformCode).queryFirst();
		if(entity ==null || entity.getId()==null){
			return R.error("未查询到对应的收款平台账号管理信息");
		}

		return addOrAccrual(vgsbm, entity.getMid(), entity.getCode(), entity.getName(),entity.getPlatformName(),
				"2120120239008552", "86-18559907949", "WorldFirst", "問前集團控股有限公司",
		1,preAmount,invoicingAmount,withholdAmount,preReturnAmount, userId,fromType,fromBid,fromBid);
	}


	//计算累计
	public List<TcwOperateCompanyPrepayment> accrual(List<TcwOperateCompanyPrepayment> infoList,List<TcwOperateCompanyPrepayment> oldMonthList){
		List<TcwOperateCompanyPrepayment> backList = new ArrayList<>();
		if(oldMonthList!=null && oldMonthList.size()>0){
			for(TcwOperateCompanyPrepayment item:infoList){
				String vgsbm = item.getVgsbm();//运营公司编码
				List<TcwOperateCompanyPrepayment> oldMonthListByVgsbm = oldMonthList
						.stream()
						.filter(oldItem->oldItem.getVgsbm().equals(vgsbm))
						.collect(Collectors.toList());
				if(oldMonthListByVgsbm.size()>0){
					TcwOperateCompanyPrepayment oldInfo = oldMonthListByVgsbm.get(0);
					item.setPreAmount(item.getPreAmount().add(oldInfo.getPreAmount()));//预付款金额
					item.setInvoicingAmount(item.getInvoicingAmount().add(oldInfo.getInvoicingAmount()));//开票金额
					item.setWithholdAmount(item.getWithholdAmount().add(oldInfo.getWithholdAmount()));//代扣代缴金额
					item.setPreReturnAmount(item.getPreReturnAmount().add(oldInfo.getPreReturnAmount()));//预付款退回金额
					item.setPreResAmount(item.getPreResAmount().add(oldInfo.getPreResAmount()));//预付款剩余金额
				}else {
					backList.add(item);
				}
			}
		}else {
			return infoList;
		}
		return backList;
	}



	//获取统计数据
	public List<TcwOperateCompanyPrepayment> getCount(List<TcwOperateCompanyPrepayment> infoList,String countMonth){
		String monthMin =  countMonth + "-01";//月份第一天
		String monthMax =  countMonth + "-" +DateUtil.getMonthLastDay(countMonth);//月份最后一天日期
		String startTime = monthMin + " 00:00:00";
		String endTime = monthMax + " 23:59:59";
		List<TcwOperateCompanyPrepayment> newList = new ArrayList<>();
		//获取统计数据
		//预付款金额 => 预付款认领单（TCW_CapitalBusinessCostSon） + 万里汇预付款入账单（TCW_WanliPrepaymentRecordedItem）
		List<Map<String, Object>> capitalBusinessCostCount  = financeMapper.getCapitalBusinessCostCount(startTime,endTime);//预付款认领单
		List<Map<String, Object>> wanliPrepaymentRecordedCount  = financeMapper.getWanliPrepaymentRecordedCount(startTime,endTime);//万里汇预付款入账单

		//开票金额：参照历史电子发票金额和形式发票金额
		List<Map<String, Object>> electronicInvoiceCount  = financeMapper.getElectronicInvoiceCount(countMonth);//电子发票金额
		List<Map<String, Object>> proformaInvoiceCount  = financeMapper.getProformaInvoiceCount(startTime,endTime);//形式发票金额

		//代扣代缴 => 交易类型为：仓储服务→快递费及运费、运营服务→VAT税费、运营服务→透明计划标签费用
		List<Map<String, Object>> withholdAmountCount  = financeMapper.getWithholdAmountCount(startTime,endTime);

		//预付款退回金额 = 预付款退回申请 -> 支付成功的
		List<Map<String, Object>> preReturnAmountCount  = financeMapper.getPreReturnAmountCount(startTime,endTime);

		for(TcwOperateCompanyPrepayment infoItem:infoList){
			BigDecimal preAmount = BigDecimal.ZERO;//预付款金额
			BigDecimal invoicingAmount = BigDecimal.ZERO;//开票金额
			BigDecimal withholdAmount = BigDecimal.ZERO;//代扣代缴金额
			BigDecimal preReturnAmount = BigDecimal.ZERO;//预付款退回金额
			BigDecimal preResAmount = BigDecimal.ZERO;//预付款剩余金额
			String vgsbm = infoItem.getVgsbm();//运营公司编码

			//根据运营公司编码，从统计信息中获取对应的金额
			//Function<T,R> 根据传入的T类型数据，返回R类型数据
			Function<List<Map<String, Object>>,BigDecimal> getAmountByVgsbm = countList -> {
				BigDecimal amount = BigDecimal.ZERO;
				List<Map<String, Object>> countListByVgsbm = countList.stream()
						.filter(item->item.get("vgsbm")!=null && item.get("vgsbm").toString().equals(vgsbm))
						.collect(Collectors.toList());
				logger.info("公司："+vgsbm+"的统计数据："+countListByVgsbm);
				if(countListByVgsbm.size()>0 && countListByVgsbm.get(0).get("amountTotal")!=null){
					amount = new BigDecimal(countListByVgsbm.get(0).get("amountTotal").toString());
				}
				return amount;
			};

			//获取各个统计对应金额
			logger.info("开始汇总公司："+vgsbm+"的：预付款金额 => 预付款认领单 + 万里汇预付款入账单");
			BigDecimal capitalBusinessCostAmount = getAmountByVgsbm.apply(capitalBusinessCostCount);//预付款认领单金额
			BigDecimal wanliPrepaymentRecordedAmount = getAmountByVgsbm.apply(wanliPrepaymentRecordedCount);//万里汇预付款入账单金额
			preAmount = capitalBusinessCostAmount
					.add(wanliPrepaymentRecordedAmount)
					.setScale(2, BigDecimal.ROUND_HALF_UP);//预付款金额 => 预付款认领单 + 万里汇预付款入账单

			logger.info("开始汇总公司："+vgsbm+"的：开票金额：参照历史电子发票金额和形式发票金额");
			BigDecimal electronicInvoiceAmount = getAmountByVgsbm.apply(electronicInvoiceCount);//电子发票金额
			BigDecimal proformaInvoiceAmount = getAmountByVgsbm.apply(proformaInvoiceCount);//形式发票金额
			invoicingAmount = electronicInvoiceAmount
					.add(proformaInvoiceAmount)
					.setScale(2, BigDecimal.ROUND_HALF_UP);//开票金额 => 电子发票金额 + 形式发票金额

			logger.info("开始汇总公司："+vgsbm+"的：代扣代缴");
			withholdAmount = getAmountByVgsbm.apply(withholdAmountCount);//代扣代缴
			logger.info("开始汇总公司："+vgsbm+"的：预付款退回金额");
			preReturnAmount = getAmountByVgsbm.apply(preReturnAmountCount);//预付款退回金额


			//预付款剩余金额 = 预付款金额-开票金额-代扣代缴-预付款退回金额
			preResAmount = preAmount //预付款金额
					.subtract(invoicingAmount) //开票金额
					.subtract(withholdAmount) //代扣代缴金额
					.subtract(preReturnAmount); //预付款退回金额

			infoItem.setPreAmount(preAmount);//预付款金额
			infoItem.setInvoicingAmount(invoicingAmount);//开票金额
			infoItem.setWithholdAmount(withholdAmount);//代扣代缴金额
			infoItem.setPreReturnAmount(preReturnAmount);//预付款退回金额
			infoItem.setPreResAmount(preResAmount);//预付款剩余金额
			infoItem.setVgsbm(vgsbm);
			newList.add(infoItem);
		}

		return newList;
	}


	//去空格
	public Map<String,Object> doTrim(Map<String, Object> params){
		Map<String,Object> paramsAfterTrim = new HashMap<>();
		for (Map.Entry<String, Object> entry : params.entrySet()) {
			String key = entry.getKey();
			Object value = entry.getValue();

			if(key.equals("fkVid") || key.equals("fkVyhzh") || key.equals("fkVkhh") || key.equals("fkVyhzhmc")
			||key.equals("vid") || key.equals("vyhzh") || key.equals("vkhh") || key.equals("vyhzhmc")){

				if(value!=null){
					String valueByStr = value.toString().trim();
					paramsAfterTrim.put(key,valueByStr);
				}
			}else {
				paramsAfterTrim.put(key,value);
			}
		}
		return paramsAfterTrim;
	}

	/**
	 * 参数验证
	 */
	public String checkParams(Map<String, Object> params, Long menuId) throws Exception {
		//获取pc字段数据
		List<YsCol> listField = new YsCol()
				.where("A.MenuId = "+menuId)
				.setOrderby("A.SortNo ASC")
				.queryList();
		//验证必填字段的非空；其他字段的长度限制、类型
		String backMsg = checkUtil.checkTableColLengthAndDataType("TCW_OperateCompanyPrepayment",listField,params,ysColItem->ysColItem.getFormEditRequired()!=null && ysColItem.getFormEditRequired() == 1);




		return backMsg;
	}


}
